﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
using Microsoft.Devices.Sensors;
using Tranquillity;
using Tranquillity.Helpers;

namespace GalaxyDefenderChaos
{
    public class Stage : VisibleGameEntity
    {
        List<EndGameListener> _EndGameListeners = new List<EndGameListener>();
        List<BackToMainMenuListener> _BackToMainMenuListeners = new List<BackToMainMenuListener>();
        GraphicsDeviceManager _graphics;
        CylinderSkyBox _SkyBox;

        Camera _camera;
        ContentManager _content;
        GraphicsDevice _graphicsDevice;
        Accelerometer _motion;

        double x, y, z;
        SoundCenter _SoundCenter;
        private Song _BackgroundSound;
        string _BackgroundSoundString = "Sound/BackgroundStage";

        SpriteBatch spriteBatch;

        My2DButton _shootButton;

        string _ExplosionSoundStr = "Sound/ExploisionSound";
        SoundEffect _ExplosionSoundEffect;
        string _MissleFireStr = "Sound/MissleFire";
        SoundEffect _MissleFire;

        List<CModel> _spaceShipTeam1s = new List<CModel>();
        List<CModel> _spaceShipTeam2s = new List<CModel>();
        CModel _playerModel;
        List<CModel> _rocketTeam1s = new List<CModel>();
        List<CModel> _rocketTeam2s = new List<CModel>();
        ParticleManager _ParticleManger;
        ExplosionParticleSystem _ExplosionParticleSystem;
       
        private SpriteFont _SpriteFont;
        private My2DButton _backButton;

        Configuration _config;

        public Stage(ContentManager content, GraphicsDevice graphicsDevice, Camera camera, SoundCenter soundCenter, GraphicsDeviceManager graphics, Game game, Configuration config)
        {
            _config = config;
            _graphics = graphics;
            spriteBatch = new SpriteBatch(graphicsDevice);
            _BackgroundSound = content.Load<Song>(_BackgroundSoundString);
            _graphicsDevice = graphicsDevice;
            _content = content;
            _camera = camera;
            _motion = new Accelerometer();
            _motion.ReadingChanged += new EventHandler<AccelerometerReadingEventArgs>(_motion_ReadingChanged);
            _motion.Start();
            _SoundCenter = soundCenter;

            //load skybox
            _SkyBox = content.Load<CylinderSkyBox>("SkyBox/Space");

            //load spaceship
            _playerModel = CreateRandomModelByName(content, graphicsDevice, camera);//new SpaceShip(content.Load<Model>("SpaceShip/Robot"),
                                           //new Vector3(0, 400, 0), Vector3.Zero, new Vector3(0.4f),
                                           //graphicsDevice, 1, content, camera);
            ((SpaceShip)_playerModel).IsDrawHPBar = false;

            _spaceShipTeam2s.Add(CreateRandomModelByName(content, graphicsDevice, camera));
                //new SpaceShip(content.Load<Model>("SpaceShip/ThunderBird"),
                //                           new Vector3(0, 400, -10000), Vector3.Zero, new Vector3(0.4f),
                //                           graphicsDevice, 2, content, camera));
            _spaceShipTeam2s.Add(CreateRandomModelByName(content, graphicsDevice, camera));
                //new SpaceShip(content.Load<Model>("SpaceShip/Ship"),
                //                           new Vector3(0, 400, -10000), Vector3.Zero, new Vector3(0.4f),
                //                           graphicsDevice, 2, content, camera)););
            _spaceShipTeam1s.Add(CreateRandomModelByName(content, graphicsDevice, camera));
                
                //new SpaceShip(content.Load<Model>("SpaceShip/CyberPlane"),
                //                           new Vector3(5000, 400, -5000), Vector3.Zero, new Vector3(0.4f),
                //                           graphicsDevice, 1, content, camera));

              ((SpaceShip)_playerModel).DelaytimeReloadOffset = 3000;

            //_spaceShipTeam2s.Add(new SpaceShip(content.Load<Model>("SpaceShip/ThunderBird"),
            //                               new Vector3(0, 400, -10000), Vector3.Zero, new Vector3(0.4f),
            //                               graphicsDevice, 2, content, camera));
            //_spaceShipTeam2s.Add(new SpaceShip(content.Load<Model>("SpaceShip/Ship"),
            //                               new Vector3(0, 400, -10000), Vector3.Zero, new Vector3(0.4f),
            //                               graphicsDevice, 2, content, camera));
            _spaceShipTeam2s.Add(new SpaceShip(content.Load<Model>("SpaceShip/CyberPlane"),
                                           new Vector3(5000, 400, -5000), Vector3.Zero, new Vector3(0.4f),
                                           graphicsDevice, 2, content, camera));

            //load button
            _shootButton = new My2DButton(_content, "PreShoot", new Vector2(_graphics.PreferredBackBufferWidth - 128 * 1.5f, _graphics.PreferredBackBufferHeight - 128 * 1.5f), new Vector2(128, 128));
            _backButton = new My2DButton(_content, "BackButton", new Vector2(0,0), new Vector2(50, 50));

            _ExplosionSoundEffect = content.Load<SoundEffect>(_ExplosionSoundStr);
            _MissleFire = content.Load<SoundEffect>(_MissleFireStr);

            _ParticleManger = new ParticleManager(game);
            _ExplosionParticleSystem = new ExplosionParticleSystem(50, content.Load<Texture2D>("ExplosionParticle"));
            _ParticleManger.AddParticleSystem(_ExplosionParticleSystem, BlendState.Additive);

            _SpriteFont = content.Load<SpriteFont>("hudFont");
        }

        public CModel CreateRandomModelByName(ContentManager content, GraphicsDevice graphicsDevice, Camera camera)
        {
            string[] modelNames = { 
                                  "SpaceShip/CyberPlane",
                                  "SpaceShip/Dolphil",
                                  "SpaceShip/LittleFighter",
                                  "SpaceShip/Ship",      
                                  };
            Random randomGenerator = new Random();
            int index = randomGenerator.Next(modelNames.Length);
            return new SpaceShip(content.Load<Model>(modelNames[index]),
                                           new Vector3(randomGenerator.Next(1000), 400, randomGenerator.Next(1000)), Vector3.Zero, new Vector3(0.4f),
                                           graphicsDevice, 1, content, camera);
        }

        public void AddEndGameListener(EndGameListener listener)
        {
            _EndGameListeners.Add(listener);
        }

        public void AddBackToMainMenuListener(BackToMainMenuListener listener)
        {
            _BackToMainMenuListeners.Add(listener);
        }

        public void ExplosionParticleAt(Vector3 position)
        {
            int numExplosionParticles = 15;
            const float sidewaysVelocityRange = 60;
            const float verticalVelocityRange = 40;
            Vector3 velocity = new Vector3();
            velocity.X = (float)(RandomHelper.Random.NextDouble() - 0.5) * sidewaysVelocityRange;
            velocity.Y = (float)(RandomHelper.Random.NextDouble() + 0.5) * verticalVelocityRange;
            velocity.Z = (float)(RandomHelper.Random.NextDouble() - 0.5) * sidewaysVelocityRange;
            for (int i = 0; i < numExplosionParticles; i++)
                _ExplosionParticleSystem.AddParticle(
                    position,
                    RandomHelper.ColorBetween(Color.DarkGray, Color.Gray),
                    velocity * 0.01f + new Vector3(RandomHelper.FloatBetween(-30, 30), RandomHelper.FloatBetween(30, -10), RandomHelper.FloatBetween(-30, 30)) * 0.05f,
                    RandomHelper.FloatBetween(-0.01f, 0.01f),
                    TimeSpan.FromSeconds(RandomHelper.IntBetween(1, 2)),
                    true,
                    RandomHelper.FloatBetween(0.0f, MathHelper.Pi),
                    0.1f);
        }

        public void PlaySound()
        {
            _SoundCenter.playLoopSound(_BackgroundSound);
        }

        public void StopSound()
        {
            _SoundCenter.pauseLoopSound();
        }

        void _motion_ReadingChanged(object sender, AccelerometerReadingEventArgs e)
        {
            x = e.X;
            y = e.Y;
            z = e.Z;
        }

        public override void Update(GameTime gameTime, TouchCollection touchCollection)
        {
            CheckBackButton(touchCollection);
            updateModelPlayer(gameTime, touchCollection);
            updateCamera(gameTime, touchCollection);
            for (int i = 0; i < _rocketTeam1s.Count; i++)
            {
                _rocketTeam1s[i].Update(gameTime, touchCollection);
            }
            for (int i = 0; i < _rocketTeam2s.Count; i++)
            {
                _rocketTeam2s[i].Update(gameTime, touchCollection);
            }
            for (int i = 0; i < _spaceShipTeam1s.Count; i++)
            {
                _spaceShipTeam1s[i].Update(gameTime, touchCollection);
            }
            for (int i = 0; i < _spaceShipTeam2s.Count; i++)
            {
                _spaceShipTeam2s[i].Update(gameTime, touchCollection);
            }
            _playerModel.Update(gameTime, touchCollection);
            //player////////////////////////////////////////
            CModel target = FindTargetOfPlayer();
            if (target != null)
            {
                //Vector2 touchPoint = new Vector2(touchCollection[0].Position.X, touchCollection[0].Position.Y);
                UpdateCheckButton(gameTime, touchCollection, target);
            }
            ////////////////////////////////////////////////
            for (int i = 0; i < _rocketTeam1s.Count; i++)
            {
                if (ChaseObjectShoot(gameTime, _rocketTeam1s[i]))
                    i--;
            }
            for (int i = 0; i < _rocketTeam2s.Count; i++)
            {
                if (ChaseObjectShoot(gameTime, _rocketTeam2s[i]))
                    i--;
            }
            ObjectMovePC(gameTime, touchCollection);
            AIActive(gameTime);
            CheckWin();

            base.Update(gameTime, touchCollection);
        }

        private void CheckBackButton(TouchCollection touchCollection)
        {
            if (touchCollection.Count > 0 && touchCollection[0].State == TouchLocationState.Pressed)
            {
                Vector2 touchPoint = new Vector2(touchCollection[0].Position.X, touchCollection[0].Position.Y);
                if (_backButton.CheckInside(touchPoint))
                {
                    for (int i = 0; i < _BackToMainMenuListeners.Count; i++)
                    {
                        _BackToMainMenuListeners[i].BackToMainMenuSelected();
                    }
                }
            }
        }

        private void AIType1(GameTime gameTime, List<CModel> team1, List<CModel> team2)
        {
            for (int i = 0; i < team1.Count; i++)
            {
                CModel target = ((SpaceShip)team1[i]).FindNearObject(team2);
                if (target != null)
                {
                    ((SpaceShip)team1[i]).ChaseObject(gameTime, target);
                    if (((SpaceShip)team1[i]).TimeReloadRocket >= ((SpaceShip)team1[i]).DelaytimeReloadOffset)
                    {
                        ((SpaceShip)team1[i]).TimeReloadRocket = 0;
                        CModel r = new Rocket(_content.Load<Model>("Rocket/Rocket"),
           team1[i].Position, Vector3.Zero, new Vector3(1.5f),
           _graphicsDevice, team1[i], target);
                        _rocketTeam1s.Add(r);
                    }
                }
            }
        }

        public void AIActive(GameTime gameTime)
        {
            {
                if (_config.DifficutyLevel == 0)
                {
                    _spaceShipTeam1s.Add(_playerModel);
                    AIType1(gameTime, _spaceShipTeam2s, _spaceShipTeam1s);
                    _spaceShipTeam1s.Remove(_playerModel);
                    AIType1(gameTime, _spaceShipTeam1s, _spaceShipTeam2s);
                }
                else
                {
                    _spaceShipTeam1s.Add(_playerModel);
                    AIType1(gameTime, _spaceShipTeam2s, _spaceShipTeam1s);
                    _spaceShipTeam1s.Remove(_playerModel);
                    AIType2(gameTime, _spaceShipTeam1s, _spaceShipTeam2s, _rocketTeam2s);
                }
            }
        }

        //private void AIType1(GameTime gameTime, List<CModel> team1, List<CModel> team2)
        //{
        //    for (int i = 0; i < team1.Count; i++)
        //    {
        //        CModel target = ((SpaceShip)team1[i]).FindNearObject(team2);
        //        if (target != null)
        //        {
        //            double tempLenghth = Math.Sqrt(
        //                Math.Pow(team1[i].Position.X - target.Position.X, 2) +
        //                Math.Pow(team1[i].Position.Y - target.Position.Y, 2) +
        //                Math.Pow(team1[i].Position.Z - target.Position.X, 2));
        //            if (tempLenghth > 10000)
        //                team1[i].ChaseObject(gameTime, target);
        //            if (((SpaceShip)team1[i]).TimeReloadRocket >= ((SpaceShip)team1[i]).DelaytimeReloadOffset)
        //            {
        //                ((SpaceShip)team1[i]).TimeReloadRocket = 0;
        //                CModel r = new Rocket(_content.Load<Model>("Rocket/Rocket"),
        //   team1[i].Position, Vector3.Zero, new Vector3(1.5f),
        //   _graphicsDevice, team1[i], target);
        //                _rocketTeam1s.Add(r);
        //            }
        //        }
        //    }
        //}

        public void CheckWin()
        {
            if (_spaceShipTeam2s.Count == 0)
            {
                for (int i = 0; i < _EndGameListeners.Count; i++)
                    _EndGameListeners[i].YouWin();
            }
            if (((SpaceShip)_playerModel).Hp <= 0)
            {
                for (int i = 0; i < _EndGameListeners.Count; i++)
                    _EndGameListeners[i].YouLose();
            }
        }
       
        //stage
        public bool ChaseObjectShoot(GameTime gameTime, CModel rocket)
        {
            CModel target = ((Rocket)rocket).Target;
            rocket.ChaseObject(gameTime, target);
            if (((Rocket)rocket).TimeLife <= 0)
            {
                RocketBurnWithoutCollision(rocket);
                return true;
            }
            if(target != null)
            if (rocket.BoundingSphere.Intersects(target.BoundingSphere))
            {
                if (_rocketTeam1s.Contains(rocket))
                {
                    if (_spaceShipTeam1s.Contains(target))
                    {
                        ((SpaceShip)target).Hp -= 30;
                        if (((SpaceShip)target).Hp <= 0)
                            _spaceShipTeam1s.Remove(target);
                    }
                    if (_spaceShipTeam2s.Contains(target))
                    {
                        ((SpaceShip)target).Hp -= 30;
                        if (((SpaceShip)target).Hp <= 0)
                            _spaceShipTeam2s.Remove(target);
                    }
                    if (_playerModel == target)
                    {
                        ((SpaceShip)target).Hp -= 30;
                    }
                    ExplosionParticleAt(rocket.Position);
                    _SoundCenter.playSoundEffect(_ExplosionSoundEffect);
                    _rocketTeam1s.Remove(rocket);
                }
                RocketBurnWithoutCollision(rocket);
                return true;
            }
            return false;
        }

        private void RocketBurnWithoutCollision(CModel rocket)
        {
            if (_rocketTeam2s.Contains(rocket))
            {
                ExplosionParticleAt(rocket.Position);
                _SoundCenter.playSoundEffect(_ExplosionSoundEffect);
                _rocketTeam2s.Remove(rocket);
            }
            if (_rocketTeam1s.Contains(rocket))
            {
                ExplosionParticleAt(rocket.Position);
                _SoundCenter.playSoundEffect(_ExplosionSoundEffect);
                _rocketTeam1s.Remove(rocket);
            }
        }

        //test demo
        private void ObjectMovePC(GameTime gameTime, TouchCollection touchCollection)
        {
            float speed = 5;
            Vector3 rotChange = new Vector3(0, 1, 0);
            for (int i = 0; i < _spaceShipTeam2s.Count; i++)
            {
                _spaceShipTeam2s[i].Rotation += rotChange * .025f;

                Matrix rotation = Matrix.CreateFromYawPitchRoll(
                    _spaceShipTeam2s[i].Rotation.Y, _spaceShipTeam2s[i].Rotation.X,
                    _spaceShipTeam2s[i].Rotation.Z);

                _spaceShipTeam2s[i].Position += Vector3.Transform(Vector3.Forward,
                rotation) * (float)gameTime.ElapsedGameTime.TotalMilliseconds * speed;

                //_spaceShipTeam1s[0].ChaseObject(gameTime, _spaceShipTeam2s[i]);
            }
        }


        //stage
        public CModel FindTargetOfPlayer()
        {
            CModel target = null;
            List<CModel> listObjectInView = new List<CModel>();
            foreach (CModel model in _spaceShipTeam2s)
                if (_camera.BoundingVolumeIsInView(model.BoundingSphere))
                    listObjectInView.Add(model);
            foreach (CModel model in _rocketTeam2s)
                if (_camera.BoundingVolumeIsInView(model.BoundingSphere))
                    listObjectInView.Add(model);
            target = ((SpaceShip)_playerModel).FindNearObject(listObjectInView);
            return target;
        }


        //stage
        private void UpdateCheckButton(GameTime gameTime, TouchCollection touchCollection, CModel target)
        {
            if (touchCollection.Count > 0 && touchCollection[0].State == TouchLocationState.Pressed)
            {
                Vector2 touchPoint = new Vector2(touchCollection[0].Position.X, touchCollection[0].Position.Y);
                if (_shootButton.CheckInside(touchPoint))
                {
                    if (((SpaceShip)_playerModel).TimeReloadRocket >= ((SpaceShip)_playerModel).DelaytimeReloadOffset)
                    {
                        ((SpaceShip)_playerModel).TimeReloadRocket = 0;
                        CModel r = new Rocket(_content.Load<Model>("Rocket/Rocket"),
       _playerModel.Position, Vector3.Zero, new Vector3(1.5f),
       _graphicsDevice, _playerModel, target);
                        _rocketTeam1s.Add(r);
                        _SoundCenter.playSoundEffect(_MissleFire);
                    }
                }
            }
            _ParticleManger.SetMatrices(_camera.View, _camera.Projection);
        }

        //stage
        void updateModelPlayer(GameTime gameTime, TouchCollection touchCollection)
        {
            Vector3 rotChange = new Vector3(0, 0, 0);
            // Determine on which axes the ship should be rotated on, if any
            //if (z > 0.1f)
            //    rotChange += new Vector3((float)z * 1, 0, 0);
            //if (z < -0.1f)
            //    rotChange += new Vector3((float)z * 1, 0, 0);
            if (y > 0.1f)
                rotChange += new Vector3(0, (float)y * 5, 0);
            if (y < -0.1f)
                rotChange += new Vector3(0, (float)y * 5, 0);
            _playerModel.Rotation += rotChange * .025f;

            // Determine what direction to move in
            Matrix rotation = Matrix.CreateFromYawPitchRoll(
                _playerModel.Rotation.Y, _playerModel.Rotation.X,
                _playerModel.Rotation.Z);
            // Move in the direction dictated by our rotation matrix

            float speed = 0;
            if (z <= 0f)
                speed = 0;
            if (z <= -0.2f)
                speed = 1;
            if (z <= -0.4f)
                speed = 2;
            if (z <= -0.6f)
                speed = 3;
            if (z <= -0.8f)
                speed = 4;
            if (z <= -1f)
                speed = 5;

            _playerModel.Position += Vector3.Transform(Vector3.Forward,
            rotation) * (float)gameTime.ElapsedGameTime.TotalMilliseconds *
            speed * 2;

            //_playerModel.Update(gameTime, touchCollection);
        }

        //stage
        void updateCamera(GameTime gameTime, TouchCollection touchCollection)
        {
            // Move the camera to the new model's position and orientation
            ((ChaseCamera)_camera).Move(_playerModel.Position,
              _playerModel.Rotation);
            // Update the camera
            _camera.Update();
        }

        //stage
        public override void Draw(Microsoft.Xna.Framework.Graphics.GraphicsDevice graphicsDevice, Camera camera, GameTime gameTime)
        {
            _SkyBox.Draw(graphicsDevice, camera, gameTime);

            if (_camera.BoundingVolumeIsInView(_playerModel.BoundingSphere))
            {
                _playerModel.Draw(_camera.View, _camera.Projection);
            }
            DrawHpInfor(graphicsDevice);

            DrawObject(_spaceShipTeam1s, graphicsDevice, camera, gameTime);
            DrawObject(_spaceShipTeam2s, graphicsDevice, camera, gameTime);
            DrawObject(_rocketTeam1s, graphicsDevice, camera, gameTime);
            DrawObject(_rocketTeam2s, graphicsDevice, camera, gameTime);

            _shootButton.Draw(_graphicsDevice, _camera, gameTime, new Color(1, 1, 1, 0.1f));
            _backButton.Draw(_graphicsDevice, _camera, gameTime, new Color(1, 1, 1, 0.1f));
        }

        private void DrawObject(List<CModel> models, GraphicsDevice graphicsDevice, Camera camera, GameTime gameTime)
        {
            foreach (CModel model in models)
                if (_camera.BoundingVolumeIsInView(model.BoundingSphere))
                    model.Draw(graphicsDevice, camera, gameTime);
        }

        void DrawHpInfor(GraphicsDevice graphicsDevice)
        {
            SpriteBatch spriteBatch = new SpriteBatch(graphicsDevice);
            spriteBatch.Begin();

            spriteBatch.DrawString(_SpriteFont, ("HP: " + ((SpaceShip)_playerModel).Hp + "/100"), new Vector2(50, 50), Color.Red);

            spriteBatch.End();
        }
    }
}
